import { defineComponent, h, ref, toRef, inject, Ref } from 'vue'
import './index.less'

import {
  ResizingHandle,
  ResizingHandleStore,
  ContainerProvider,
  UpdatePosition,
  GetPositionStore,
  SetMatchedLine,
} from './types'

import { filterHandles, getElSize, IDENTITY, directionMap } from './utils'

import {
  initState,
  initParent,
  initLimitSizeAndMethods,
  initDraggableContainer,
  initResizeHandle,
  watchProps,
  initRotateHandle,
} from './hooks'

// top-left top-middle  top-right
// middle-left middle-right
// bottom-left bottom-middle bottom-right
export const ALL_HANDLES: ResizingHandleStore[] = [
  {
    direction: 'tl',
    translate: '-50%, -50%',
  },
  {
    direction: 'tm',
    translate: '-50%, -50%',
  },
  {
    direction: 'tr',
    translate: '50%, -50%',
  },
  {
    direction: 'ml',
    translate: '-50%, -50%',
  },
  {
    direction: 'mr',
    translate: '50%, -50%',
  },
  {
    direction: 'bl',
    translate: '-50%, 50%',
  },
  {
    direction: 'bm',
    translate: '-50%, 50%',
  },
  {
    direction: 'br',
    translate: '50%, 50%',
  },
]

const drrProps = {
  // 初始化宽高
  initW: {
    type: Number,
    default: null,
  },
  initH: {
    type: Number,
    default: null,
  },
  // 宽高 变化
  w: {
    type: Number,
    default: 0,
  },
  h: {
    type: Number,
    default: 0,
  },
  // left top
  x: {
    type: Number,
    default: 0,
  },
  y: {
    type: Number,
    default: 0,
  },
  // 旋转角度
  angle: {
    type: Number,
    default: 0,
  },
  // 是否可拖拽
  draggable: {
    type: Boolean,
    default: true,
  },
  // 是否可改变大小
  resizable: {
    type: Boolean,
    default: true,
  },
  // 不同方向的
  disabledX: {
    type: Boolean,
    default: false,
  },
  disabledY: {
    type: Boolean,
    default: false,
  },
  disabledW: {
    type: Boolean,
    default: false,
  },
  disabledH: {
    type: Boolean,
    default: false,
  },
  // 最小宽高
  minW: {
    type: Number,
    default: 1,
  },
  minH: {
    type: Number,
    default: 1,
  },
  // 是否激活状态
  active: {
    type: Boolean,
    default: false,
  },
  // 父元素
  parent: {
    type: Boolean,
    default: false,
  },
  // 拖拽方向
  handles: {
    type: Array,
    default: ['tl', 'tm', 'tr', 'ml', 'mr', 'bl', 'bm', 'br'],
    validator: (handles: ResizingHandle[]) => {
      return filterHandles(handles).map(i => i.direction).length === handles.length
    },
  },
  // 过程中的className
  classNameDraggable: {
    type: String,
    default: 'draggable',
  },
  classNameResizable: {
    type: String,
    default: 'resizable',
  },
  classNameDragging: {
    type: String,
    default: 'dragging',
  },
  classNameResizing: {
    type: String,
    default: 'resizing',
  },
  classNameActive: {
    type: String,
    default: 'active',
  },
  classNameHandle: {
    type: String,
    default: 'handle',
  },
  classNameRotating: {
    type: String,
    default: 'rotating',
  },
  // 按照比例缩放，任一点都是
  lockAspectRatio: {
    type: Boolean,
    default: false,
  },
  // 顶点缩放按照比例, lockAspectRatio优先级高
  vertexRatio: {
    type: Boolean,
    default: true,
  },
}

const emits = [
  'activated',
  'deactivated',
  'drag-start',
  'dragging',
  'drag-end',
  'resize-start',
  'resizing',
  'resize-end',
  'update:w',
  'update:h',
  'update:x',
  'update:y',
  'update:active',
  'rotate-start',
  'rotating',
  'rotate-end',
  'update:angle',
]

const Vue3DragResizeRotate = defineComponent({
  name: 'Vue3DragResizeRotate',
  props: drrProps,
  emits: emits,
  setup(props, { emit }) {
    console.log(props, emit)
    // 容器container的一些属性 w/h/top/left ...
    const containerProps = initState(props, emit)
    const containerRef = ref<HTMLElement>()
    let containerProvider: ContainerProvider | null = null
    const provideIdentity = inject('identity')
    if (provideIdentity === IDENTITY) {
      containerProvider = {
        updatePosition: inject<UpdatePosition>('updatePosition')!,
        getPositionStore: inject<GetPositionStore>('getPositionStore')!,
        disabled: inject<Ref<boolean>>('disabled')!,
        adsorbParent: inject<Ref<boolean>>('adsorbParent')!,
        adsorbCols: inject<number[]>('adsorbCols')!,
        adsorbRows: inject<number[]>('adsorbRows')!,
        setMatchedLine: inject<SetMatchedLine>('setMatchedLine')!,
      }
    }

    // 初始化parent宽高
    const parentSize = initParent(containerRef)
    // 范围确定
    const limitProps = initLimitSizeAndMethods(props, containerProps, parentSize)
    // 初始化container
    initDraggableContainer(
      containerRef,
      containerProps,
      limitProps,
      toRef(props, 'draggable'),
      emit,
      containerProvider,
      parentSize
    )
    // 初始化handles
    const resizeHandle = initResizeHandle(
      containerRef,
      containerProps,
      limitProps,
      parentSize,
      props,
      emit
    )

    // 初始化rotate
    const rotateHandle = initRotateHandle(containerRef, containerProps, props, emit)
    // 监听props.(w、h、x、y)
    watchProps(props, limitProps)

    return {
      containerRef,
      ...containerProps,
      ...parentSize,
      ...limitProps,
      ...resizeHandle,
      ...rotateHandle,
      containerProvider,
    }
  },
  computed: {
    style(): { [propName: string]: string } {
      return {
        width: this.width + 'px',
        height: this.height + 'px',
        top: this.top + 'px',
        left: this.left + 'px',
        transform: `rotate(${this.angle}deg)`,
      }
    },
    classNames(): { [propName: string]: string | boolean } {
      return {
        [this.classNameActive]: this.enable, // enable props.active
        [this.classNameDragging]: this.dragging,
        [this.classNameResizing]: this.resizing,
        [this.classNameDraggable]: this.draggable,
        [this.classNameResizable]: this.resizable,
        [this.classNameRotating]: this.rotating,
      }
    },
    getRotation(d: string) {
      return (d: string): number => {
        let rotate = directionMap[d] + Math.floor((this.angle + 7.5) / 15) * 15
        if (rotate > 180) {
          rotate = rotate - 180
        }
        if (rotate < 0) {
          rotate = 180 + rotate
        }
        if (rotate > 165) {
          rotate = 0
        }
        return rotate
      }
    },
  },
  mounted() {
    if (!this.containerRef) return
    this.containerRef.ondragstart = () => false
    const { width, height } = getElSize(this.containerRef)
    this.setWidth(this.initW === null ? this.w || width : this.initW)
    this.setHeight(this.initH === null ? this.h || height : this.initH)
    if (this.containerProvider) {
      this.containerProvider.updatePosition(this.id, {
        x: this.left,
        y: this.top,
        w: this.width,
        h: this.height,
        angle: this.angle,
      })
    }
  },

  render() {
    // h(标签, {属性},内容)
    // h(标签, {属性},[可以继续嵌套h()])
    return h(
      'div',
      {
        ref: 'containerRef',
        class: ['vdr-container', this.classNames],
        style: this.style,
      },
      [
        this.$slots.default && this.$slots.default(),
        h(
          'div',
          {
            class: ['vdr-rotate'],
            onMousedown: (e: MouseEvent) => this.rotateDown(e),
            onTouchstart: (e: TouchEvent) => this.rotateDown(e),
          },
          [
            h('div', {
              class: ['vdr-rotate-control'],
            }),
          ]
        ),
        ...this.handlesFiltered.map(item =>
          h('div', {
            class: [
              'vdr-handle',
              'vdr-handle-' + item.direction,
              this.classNameHandle,
              `${this.classNameHandle}-${item.direction}`,
            ],
            rotation: this.getRotation(item.direction),
            style: { transform: `translate(${item.translate})` },
            onMousedown: (e: MouseEvent) =>
              this.resizeHandleDown(e, <ResizingHandle>item.direction),
            onTouchstart: (e: TouchEvent) =>
              this.resizeHandleDown(e, <ResizingHandle>item.direction),
          })
        ),
        h('div', {
          class: ['vdr-line', 'vdr-line-n'],
          style: {
            width: this.width + 'px',
            transform: `translateY(-50%) translate(0,0px) rotate(0deg)`,
          },
        }),
        h('div', {
          class: ['vdr-line', 'vdr-line-s'],
          style: {
            width: this.width + 'px',
            transform: `translateY(-50%) translate(0,${this.height}px) rotate(0deg)`,
          },
        }),
        h('div', {
          class: ['vdr-line', 'vdr-line-w'],
          style: {
            width: this.height + 'px',
            transform: `translateY(-50%) translate(0,0) rotate(90deg)`,
          },
        }),
        h('div', {
          class: ['vdr-line', 'vdr-line-e'],
          style: {
            width: this.height + 'px',
            transform: `translateY(-50%) translate(${this.width}px,0) rotate(90deg)`,
          },
        }),
      ]
    )
  },
})

export default Vue3DragResizeRotate
